#ifndef _Util_H_
#define _Util_H_

#include "Vector2D.h"
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <SDL/SDL.h>

typedef Uint8 Button;

namespace Util {


inline bool linesIntersect(Vector2D p1, Vector2D p2, Vector2D p3, Vector2D p4,
                           Vector2D &intersect_point){

    float epsilon = 0.0001f;
    float denominator = (p4.y - p3.y)*(p2.x - p1.x) - (p4.x - p3.x)*(p2.y - p1.y);
    
    if(fabs(denominator) < epsilon){ return false; } // lines are parallel.
    
    float numerator1 = (p4.x - p3.x)*(p1.y - p3.y) - (p4.y - p3.y)*(p1.x - p3.x);
    float numerator2 = (p2.x - p1.x)*(p1.y - p3.y) - (p2.y - p1.y)*(p1.x - p3.x);

    float u1 = numerator1/denominator;
    float u2 = numerator2/denominator;
    
    if(u1 < -epsilon || u1 > 1.0f+epsilon){ return false; } // intesect point falls outside the segment.
    if(u2 < -epsilon || u2 > 1.0f+epsilon){ return false; }

    intersect_point.x = p1.x + u1*(p2.x - p1.x);
    intersect_point.y = p1.y + u1*(p2.y - p1.y);

    return true;
}

inline float pointSegmentDist(Vector2D point, Vector2D seg1, Vector2D seg2, Vector2D &closest_point){
    Vector2D v = seg2 - seg1;
    Vector2D w = point - seg1;

    float c1 = w.dotProduct(v);
    if(c1 <= 0.0f){
        closest_point = seg1;
        return Vector2D(point - seg1).length();
    }

    float c2 = v.dotProduct(v);
    if(c2 <= c1){
        closest_point = seg2;
        return Vector2D(point - seg2).length();

    }

    float b = c1/c2;
    Vector2D Pb = seg1 + b*v;

    closest_point = Pb;
    return Vector2D(point - Pb).length();
}


// Returns a random value in the given interval.
inline float rand_interval(float min, float max){
    float r = (float)rand()/(float)RAND_MAX;
    return r*(max-min) + min;
}

inline SDLKey parseSpecialKey(std::string str) {
    if (str == "<esc>") {
        return SDLK_ESCAPE;
    }
    if (str == "<space>") {
        return SDLK_SPACE;
    }
    if (str == "<enter>") {
        return SDLK_RETURN;
    }
    if (str == "<up>") {
        return SDLK_UP;
    }
    if (str == "<down>") {
        return SDLK_DOWN;
    }
    std::cerr << "Util.h:parseSpecialKey: implement key binding for \"" << str << "\"" << std::endl;
    return SDLK_ESCAPE;
}

inline SDLKey SDLKey_lookup(std::string str) {
    SDLKey key;
    switch (str[0]) {
        case 'w': key = SDLK_w; break;
        case 's': key = SDLK_s; break;
        case 'a': key = SDLK_a; break;
        case 'd': key = SDLK_d; break;
        case 'q': key = SDLK_q; break;
        case 'e': key = SDLK_e; break;
        case 'i': key = SDLK_i; break;
        case 'k': key = SDLK_k; break;
        case '<': key = parseSpecialKey(str); break;
        default:
            key = SDLK_ESCAPE;
            std::cerr << "Util.h:SDLKey_lookup: implement key binding for \"" << str << "\"" << std::endl;
    }
    return key;
}

inline int SDLButton_lookup(std::string str) {
    if (str == "<mouse_left>") return (int)SDL_BUTTON_LEFT;
    if (str == "<mouse_right>") return (int)SDL_BUTTON_RIGHT;
    if (str == "<scroll_up>") return (int)SDL_BUTTON_WHEELUP;
    if (str == "<scroll_down>") return (int)SDL_BUTTON_WHEELDOWN;
    std::cerr << "Util.h:SDLButton_lookup: implement button binding for \"" << str << "\"" << std::endl;
    return (int)SDL_BUTTON_WHEELDOWN;
}

}

#endif 
